package com.quad.innovators.salesease.exception;

import com.quad.innovators.salesease.common.result.Result;
import com.quad.innovators.salesease.enums.ResultCode;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 参数校验异常
     * @param e 异常
     * @return 结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(ResultCode.PARAM_CHECK_ILLEGAL.getMsg(), e);
        String violations = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).
                collect(Collectors.joining(","));
        return Result.otherErr(ResultCode.PARAM_CHECK_ILLEGAL, violations);
    }


    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<String> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error(ResultCode.PARAMS_MISSING.getMsg(), e);
        String parameterName = e.getParameterName();
        String errorMessage = String.format(ResultCode.PARAMS_MISSING.getMsg(), parameterName);
        return Result.otherErr(ResultCode.PARAMS_MISSING, errorMessage);
    }


    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error(ResultCode.PARAMS_READABLE.getMsg(), e);
        return  Result.otherErr(ResultCode.PARAMS_READABLE);
    }


    @ExceptionHandler(BindException.class)
    public Result<String> handleBindException(BindException e) {
        log.error(ResultCode.PARAMS_BIND.getMsg(), e);
        String violations = e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).
                collect(Collectors.joining(","));
        return Result.otherErr(ResultCode.PARAMS_BIND, violations);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public Result<String> handleServiceException(ConstraintViolationException e) {
        log.error(ResultCode.PARAMS_CONSTRAINT.getMsg(), e);
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = violations.iterator();
        StringBuilder message = new StringBuilder();
        while (iterator.hasNext()){
            ConstraintViolation<?> violation = iterator.next();
            message.append(violation.getMessage()).append(",");
        }
        return Result.otherErr(ResultCode.PARAMS_CONSTRAINT, message.toString());
    }


    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error(ResultCode.REQUEST_NOT_ALLOW.getMsg(), e);
        return Result.otherErr(ResultCode.REQUEST_NOT_ALLOW);
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Result<String> handleHttpMediaTypeNotSupportedException(Exception e) {
        log.error(ResultCode.UNSUPPORTED_MEDIA_TYPE.getMsg(), e);
        return Result.otherErr(ResultCode.UNSUPPORTED_MEDIA_TYPE);
    }


    @ExceptionHandler({IllegalArgumentException.class})
    public Result<String> illegalArgumentException(IllegalArgumentException e) {
        log.error(ResultCode.INTERNAL_SERVER_ERROR.getMsg(), e);
        return Result.otherErr(ResultCode.INTERNAL_SERVER_ERROR);
    }

    /**
     * 自定义异常
     * @param e 异常
     * @return 结果
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public <T> Result<T> bizExceptionHandler(BusinessException e) {
        log.error(ResultCode.INTERNAL_SERVER_ERROR.getMsg(), e);
        return Result.businessErr(e);
    }

    /**
     * 其他异常
     * @param e 异常
     * @return 结果
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result<Void> exceptionHandler(Exception e) {
        log.error(ResultCode.INTERNAL_SERVER_ERROR.getMsg(), e);
        return Result.otherErr(ResultCode.INTERNAL_SERVER_ERROR);
    }
}
